// https://docs.microsoft.com/en-us/typography/opentype/spec/name#name-ids
#[repr(u16)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum NameID {
	// Copyright notice.
	CopyrightNotice = 0,
	// Font Family name. The Font Family name is used in combination with Font Subfamily name (name ID 2), and should be shared among at most four fonts that differ only in weight or style (italic/oblique), as described below.
	Family = 1,
	// Font Subfamily name. The Font Subfamily is used in combination with Font Family name (name ID 1), and distinguishes the fonts in a group with the same Font Family name. This should be used for weight and style (italic/oblique) variants only, as described below.
	Subfamily = 2,
	// Unique font identifier.
	UniqueId = 3,
	// Full font name that reflects all family and relevant subfamily descriptors. The full font name is generally a combination of name IDs 1 and 2, or of name IDs 16 and 17, or a similar human-readable variant.
	FullName = 4,
	// Version string. Should begin with the pattern “Version <number>.<number>” (upper case, lower case, or mixed, with a space between “Version” and the number).
	Version = 5,
	// PostScript name for the font. Name ID 6 specifies a string which is used to invoke a PostScript language font that corresponds to this OpenType font. When translated to ASCII, the name string must be no longer than 63 characters and restricted to the printable ASCII subset, codes 33 to 126, except for the 10 characters '[', ']', '(', ')', '{', '}', '<', '>', '/', '%'.
	PostScriptName = 6,
	// Trademark. This is used to save any trademark notice/information for this font. Such information should be based on legal advice. This is distinctly separate from the copyright.
	Trademark = 7,
	// Manufacturer Name.
	Manufacturer = 8,
	// Designer. Name of the designer of the typeface.
	Designer = 9,
	// Description. Description of the typeface. Can contain revision information, usage recommendations, history, features, etc.
	Description = 10,
	// URL of Vendor. URL of font vendor (with protocol, e.g., http://, ftp://). If a unique serial number is embedded in the URL, it can be used to register the font.
	VendorUrl = 11,
	// URL of Designer. URL of typeface designer (with protocol, e.g., http://, ftp://).
	DesignerUrl = 12,
	// License Description.
	License = 13,
	// License Info URL. URL where additional licensing information can be found.
	LicenseUrl = 14,
	Reserved = 15,
	// Typographic Family name. The typographic family grouping doesn’t impose any constraints on the number of faces within it, in contrast with the 4-style family grouping (ID 1), which is present both for historical reasons and to express style linking groups. If name ID 16 is absent, then name ID 1 is considered to be the typographic family name. (In earlier versions of the specification, name ID 16 was known as “Preferred Family”.)
	TypographicFamily = 16,
	// Typographic Subfamily name. This allows font designers to specify a subfamily name within the typographic family grouping. This string must be unique within a particular typographic family. If it is absent, then name ID 2 is considered to be the typographic subfamily name. (In earlier versions of the specification, name ID 17 was known as “Preferred Subfamily”.)
	TypographicSubfamily = 17,
	// Compatible Full (Macintosh only). On the Macintosh, the menu name is constructed using the FOND resource. This usually matches the Full Name. If you want the name of the font to appear differently than the Full Name, you can insert the Compatible Full Name in ID 18.
	CompatibleFull = 18,
	// Sample text. This can be the font name, or any other text that the designer thinks is the best sample to display the font in.
	SampleText = 19,
	// PostScript CID findfont name. Its presence in a font means that the nameID 6 holds a PostScript font name that is meant to be used with the “composefont” invocation in order to invoke the font in a PostScript interpreter. See the definition of name ID 6.
	PostScriptCid = 20,
	// WWS Family Name. Used to provide a WWS-conformant family name in case the entries for IDs 16 and 17 do not conform to the WWS model.
	WwsFamily = 21,
	// WWS Subfamily Name.
	WwsSubfamily = 22,
	// Light Background Palette. This ID, if used in the CPAL table’s Palette Labels Array, specifies that the corresponding color palette in the CPAL table is appropriate to use with the font when displaying it on a light background such as white. Strings for this ID are for use as user interface strings associated with this palette.
	LightBackgroundPalette = 23,
	// Dark Background Palette. This ID, if used in the CPAL table’s Palette Labels Array, specifies that the corresponding color palette in the CPAL table is appropriate to use with the font when displaying it on a dark background such as black. Strings for this ID are for use as user interface strings associated with this palette.
	DarkBackgroundPalette = 24,
	// Variations PostScript Name Prefix. If present in a variable font, it may be used as the family prefix in the PostScript Name Generation for Variation Fonts algorithm.
	VariationsPostScriptNamePrefix = 25,
	Other(u16),
}
impl From<u16> for NameID {
	fn from(value: u16) -> Self {
		match value {
			0 => Self::CopyrightNotice,
			1 => Self::Family,
			2 => Self::Subfamily,
			3 => Self::UniqueId,
			4 => Self::FullName,
			5 => Self::Version,
			6 => Self::PostScriptName,
			7 => Self::Trademark,
			8 => Self::Manufacturer,
			9 => Self::Designer,
			10 => Self::Description,
			11 => Self::VendorUrl,
			12 => Self::DesignerUrl,
			13 => Self::License,
			14 => Self::LicenseUrl,
			15 => Self::Reserved,
			16 => Self::TypographicFamily,
			17 => Self::TypographicSubfamily,
			18 => Self::CompatibleFull,
			19 => Self::SampleText,
			20 => Self::PostScriptCid,
			21 => Self::WwsFamily,
			22 => Self::WwsSubfamily,
			23 => Self::LightBackgroundPalette,
			24 => Self::DarkBackgroundPalette,
			25 => Self::VariationsPostScriptNamePrefix,
			id => Self::Other(id),
		}
	}
}

#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum PlatformEncoding {
	Unicode(UnicodeEncodeId),
	Macintosh(MacintoshEncodeId),
	Iso(u16),
	Windows(WindowsEncodeId),
	Custom(u16),
}
impl PlatformEncoding {
	pub fn new(platform_id: u16, encoding_id: u16) -> Option<Self> {
		let platform_id = PlatformId::try_from(platform_id).ok()?;
		Some(match platform_id {
			PlatformId::Unicode => Self::Unicode(encoding_id.into()),
			PlatformId::Macintosh => Self::Macintosh(encoding_id.into()),
			PlatformId::Iso => Self::Iso(encoding_id.into()),
			PlatformId::Windows => Self::Windows(encoding_id.into()),
			PlatformId::Custom => Self::Custom(encoding_id.into()),
		})
	}
	pub fn platform(&self) -> PlatformId {
		match self {
			PlatformEncoding::Unicode(_) => PlatformId::Unicode,
			PlatformEncoding::Macintosh(_) => PlatformId::Macintosh,
			PlatformEncoding::Iso(_) => PlatformId::Iso,
			PlatformEncoding::Windows(_) => PlatformId::Windows,
			PlatformEncoding::Custom(_) => PlatformId::Custom,
		}
	}
	pub fn language(&self, language: u16) -> LanguageId {
		LanguageId::new(language, self.platform())
	}
	pub fn decode(&self, data: &[u8]) -> Option<String> {
		match self {
			PlatformEncoding::Unicode(_)
			| PlatformEncoding::Windows(WindowsEncodeId::UnicodeBMP)
			| PlatformEncoding::Windows(WindowsEncodeId::Symbol) => Self::string_from_utf16_be(data),
			PlatformEncoding::Macintosh(MacintoshEncodeId::Roman) => Self::string_from_mac_roman(data),
			_ => None,
		}
	}
	pub fn string_from_mac_roman(data: &[u8]) -> Option<String> {
		let mut raw_data = Vec::with_capacity(data.len());
		for b in data {
			raw_data.push(MAC_ROMAN[*b as usize]);
		}
		String::from_utf16(&raw_data).ok()
	}
	pub fn string_from_utf16_be(data: &[u8]) -> Option<String> {
		let mut name: Vec<u16> = Vec::new();
		for c in crate::opentype::LazyArray16::<u16>::new(data) {
			name.push(c);
		}
		String::from_utf16(&name).ok()
	}
}
impl core::fmt::Debug for PlatformEncoding {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		match self {
			Self::Unicode(arg0) => write!(f, "Unicode({:?})", arg0),
			Self::Macintosh(arg0) => write!(f, "Macintosh({:?})", arg0),
			Self::Iso(arg0) => write!(f, "Iso({:?})", arg0),
			Self::Windows(arg0) => write!(f, "Windows({:?})", arg0),
			Self::Custom(arg0) => write!(f, "Custom({:?})", arg0),
		}
	}
}
/// Macintosh Roman to UTF-16 encoding table.
///
/// https://en.wikipedia.org/wiki/Mac_OS_Roman
#[rustfmt::skip]
const MAC_ROMAN: &[u16; 256] = &[
    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
    0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
    0x0010, 0x2318, 0x21E7, 0x2325, 0x2303, 0x0015, 0x0016, 0x0017,
    0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
    0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
    0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
    0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
    0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
    0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
    0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
    0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
    0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
    0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
    0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
    0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
    0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
    0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
    0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
    0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
    0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
    0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
    0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02,
    0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
    0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
    0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
    0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7,
];

// https://docs.microsoft.com/en-us/typography/opentype/spec/name#platform-ids.
// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PlatformId {
	Unicode,
	Macintosh,
	Iso,
	Windows,
	Custom,
}
impl TryFrom<u16> for PlatformId {
	type Error = ();
	fn try_from(value: u16) -> Result<Self, Self::Error> {
		match value {
			0 => Ok(PlatformId::Unicode),
			1 => Ok(PlatformId::Macintosh),
			2 => Ok(PlatformId::Iso),
			3 => Ok(PlatformId::Windows),
			4 => Ok(PlatformId::Custom),
			_ => Err(()),
		}
	}
}

// https://learn.microsoft.com/en-us/typography/opentype/spec/name#unicode-platform-platform-id--0
// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html
#[repr(u16)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum UnicodeEncodeId {
	V1_0 = 0,        // Unicode 1.0 semantics—deprecated
	V1_1 = 1,        // Unicode 1.1 semantics—deprecated
	IsoIec10645 = 2, // ISO/IEC 10646 semantics—deprecated
	BMP = 3,         // Unicode 2.0 and onwards semantics, Unicode BMP only
	Full = 4,        // Unicode 2.0 and onwards semantics, Unicode full repertoire
	Variation = 5,   // Unicode variation sequences —for use with subtable format 14
	Full6 = 6,       // Unicode full repertoire —for use with subtable format 13
	Custom(u16),
}
impl From<u16> for UnicodeEncodeId {
	fn from(value: u16) -> Self {
		match value {
			0 => Self::V1_0,
			1 => Self::V1_1,
			2 => Self::IsoIec10645,
			3 => Self::BMP,
			4 => Self::Full,
			5 => Self::Variation,
			6 => Self::Full6,
			id => Self::Custom(id),
		}
	}
}

// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html
#[repr(u16)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MacintoshEncodeId {
	Roman = 0,
	Japanese = 1,
	TraditionalChinese = 2,
	Korean = 3,
	Arabic = 4,
	Hebrew = 5,
	Greek = 6,
	Russian = 7,
	RSymbol = 8,
	Devanagari = 9,
	Gurmukhi = 10,
	Gujarati = 11,
	Oriya = 12,
	Bengali = 13,
	Tamil = 14,
	Telugu = 15,
	Kannada = 16,
	Malayalam = 17,
	Sinhalese = 18,
	Burmese = 19,
	Khmer = 20,
	Thai = 21,
	Laotian = 22,
	Georgian = 23,
	Armenian = 24,
	SimplifiedChinese = 25,
	Tibetan = 26,
	Mongolian = 27,
	Geez = 28,
	Slavic = 29,
	Vietnamese = 30,
	Sindhi = 31,
	Uninterpreted = 32,
	Custom(u16),
}
impl From<u16> for MacintoshEncodeId {
	fn from(value: u16) -> Self {
		match value {
			0 => Self::Roman,
			1 => Self::Japanese,
			2 => Self::TraditionalChinese,
			3 => Self::Korean,
			4 => Self::Arabic,
			5 => Self::Hebrew,
			6 => Self::Greek,
			7 => Self::Russian,
			8 => Self::RSymbol,
			9 => Self::Devanagari,
			10 => Self::Gurmukhi,
			11 => Self::Gujarati,
			12 => Self::Oriya,
			13 => Self::Bengali,
			14 => Self::Tamil,
			15 => Self::Telugu,
			16 => Self::Kannada,
			17 => Self::Malayalam,
			18 => Self::Sinhalese,
			19 => Self::Burmese,
			20 => Self::Khmer,
			21 => Self::Thai,
			22 => Self::Laotian,
			23 => Self::Georgian,
			24 => Self::Armenian,
			25 => Self::SimplifiedChinese,
			26 => Self::Tibetan,
			27 => Self::Mongolian,
			28 => Self::Geez,
			29 => Self::Slavic,
			30 => Self::Vietnamese,
			31 => Self::Sindhi,
			32 => Self::Uninterpreted,
			id => Self::Custom(id),
		}
	}
}

// https://learn.microsoft.com/en-us/typography/opentype/spec/name#windows-platform-platform-id-3
#[repr(u16)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum WindowsEncodeId {
	Symbol = 0,
	UnicodeBMP = 1,
	ShiftJIS = 2,
	PRC = 3,
	Big5 = 4,
	Wansung = 5,
	Johab = 6,
	Reserved7 = 7,
	Reserved8 = 8,
	Reserved9 = 9,
	UnicodeFull = 10,
	Custom(u16),
}
impl From<u16> for WindowsEncodeId {
	fn from(value: u16) -> Self {
		match value {
			0 => Self::Symbol,
			1 => Self::UnicodeBMP,
			2 => Self::ShiftJIS,
			3 => Self::PRC,
			4 => Self::Big5,
			5 => Self::Wansung,
			6 => Self::Johab,
			7 => Self::Reserved7,
			8 => Self::Reserved8,
			9 => Self::Reserved9,
			10 => Self::UnicodeFull,
			id => Self::Custom(id),
		}
	}
}

#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum LanguageId {
	Unicode(UnicodeLanguageId),
	Macintosh(MacintoshLanguageId),
	Iso(u16),
	Windows(WindowsLanguageId),
	Custom(u16),
}
impl LanguageId {
	pub fn new(language_id: u16, platform_id: PlatformId) -> Self {
		match platform_id {
			PlatformId::Unicode => Self::Unicode(UnicodeLanguageId),
			PlatformId::Macintosh => Self::Macintosh(MacintoshLanguageId(language_id)),
			PlatformId::Iso => Self::Iso(language_id),
			PlatformId::Windows => Self::Windows(WindowsLanguageId(language_id)),
			PlatformId::Custom => Self::Custom(language_id),
		}
	}
}
impl core::fmt::Debug for LanguageId {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		match self {
			Self::Unicode(arg0) => write!(f, "Unicode({:?})", arg0),
			Self::Macintosh(arg0) => write!(f, "Macintosh({:?})", arg0),
			Self::Iso(arg0) => write!(f, "Iso({:?})", arg0),
			Self::Windows(arg0) => write!(f, "Windows({:?})", arg0),
			Self::Custom(arg0) => write!(f, "Custom({:?})", arg0),
		}
	}
}

// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct UnicodeLanguageId;

// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacintoshLanguageId(pub u16);
impl MacintoshLanguageId {
	pub const MACINTOSH_LANGUAGE_IDS: &[(u16, &str)] = &[
		(0, "English"),
		(1, "French"),
		(2, "German"),
		(3, "Italian"),
		(4, "Dutch"),
		(5, "Swedish"),
		(6, "Spanish"),
		(7, "Danish"),
		(8, "Portuguese"),
		(9, "Norwegian"),
		(10, "Hebrew"),
		(11, "Japanese"),
		(12, "Arabic"),
		(13, "Finnish"),
		(14, "Greek"),
		(15, "Icelandic"),
		(16, "Maltese"),
		(17, "Turkish"),
		(18, "Croatian"),
		(19, "Chinese (traditional)"),
		(20, "Urdu"),
		(21, "Hindi"),
		(22, "Thai"),
		(23, "Korean"),
		(24, "Lithuanian"),
		(25, "Polish"),
		(26, "Hungarian"),
		(27, "Estonian"),
		(28, "Latvian"),
		(29, "Sami"),
		(30, "Faroese"),
		(31, "Farsi/Persian"),
		(32, "Russian"),
		(33, "Chinese (simplified)"),
		(34, "Flemish"),
		(35, "Irish Gaelic"),
		(36, "Albanian"),
		(37, "Romanian"),
		(38, "Czech"),
		(39, "Slovak"),
		(40, "Slovenian"),
		(41, "Yiddish"),
		(42, "Serbian"),
		(43, "Macedonian"),
		(44, "Bulgarian"),
		(45, "Ukrainian"),
		(46, "Byelorussian"),
		(47, "Uzbek"),
		(48, "Kazakh"),
		(49, "Azerbaijani (Cyrillic script)"),
		(50, "Azerbaijani (Arabic script)"),
		(51, "Armenian"),
		(52, "Georgian"),
		(53, "Moldavian"),
		(54, "Kirghiz"),
		(55, "Tajiki"),
		(56, "Turkmen"),
		(57, "Mongolian (Mongolian script)"),
		(58, "Mongolian (Cyrillic script)"),
		(59, "Pashto"),
		(60, "Kurdish"),
		(61, "Kashmiri"),
		(62, "Sindhi"),
		(63, "Tibetan"),
		(64, "Nepali"),
		(65, "Sanskrit"),
		(66, "Marathi"),
		(67, "Bengali"),
		(68, "Assamese"),
		(69, "Gujarati"),
		(70, "Punjabi"),
		(71, "Oriya"),
		(72, "Malayalam"),
		(73, "Kannada"),
		(74, "Tamil"),
		(75, "Telugu"),
		(76, "Sinhalese"),
		(77, "Burmese"),
		(78, "Khmer"),
		(79, "Lao"),
		(80, "Vietnamese"),
		(81, "Indonesian"),
		(82, "Tagalog"),
		(83, "Malay (Roman script)"),
		(84, "Malay (Arabic script)"),
		(85, "Amharic"),
		(86, "Tigrinya"),
		(87, "Galla"),
		(88, "Somali"),
		(89, "Swahili"),
		(90, "Kinyarwanda/Ruanda"),
		(91, "Rundi"),
		(92, "Nyanja/Chewa"),
		(93, "Malagasy"),
		(94, "Esperanto"),
		(128, "Welsh"),
		(129, "Basque"),
		(130, "Catalan"),
		(131, "Latin"),
		(132, "Quechua"),
		(133, "Guarani"),
		(134, "Aymara"),
		(135, "Tatar"),
		(136, "Uighur"),
		(137, "Dzongkha"),
		(138, "Javanese (Roman script)"),
		(139, "Sundanese (Roman script)"),
		(140, "Galician"),
		(141, "Afrikaans"),
		(142, "Breton"),
		(143, "Inuktitut"),
		(144, "Scottish Gaelic"),
		(145, "Manx Gaelic"),
		(146, "Irish Gaelic (with dot above)"),
		(147, "Tongan"),
		(148, "Greek (polytonic)"),
		(149, "Greenlandic"),
		(150, "Azerbaijani (Roman script)"),
	];
	pub fn to_str(&self) -> Option<&'static str> {
		Self::MACINTOSH_LANGUAGE_IDS
			.binary_search_by_key(&self.0, |v| v.0)
			.map(|v| Self::MACINTOSH_LANGUAGE_IDS.get(v).map(|v| v.1))
			.ok()
			.flatten()
	}
}
impl core::fmt::Debug for MacintoshLanguageId {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		write!(f, "{}", self.to_str().unwrap_or("Unkonw"))
	}
}

// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/63d3d639-7fd2-4afb-abbe-0d5b5551eef8
// version 4/23/2024 16.0
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct WindowsLanguageId(pub u16);
impl WindowsLanguageId {
	pub const WINDOWS_LANGUAGE_IDS: &[(u16, &str)] = &[
		(0x0001, "ar"),
		(0x0002, "bg"),
		(0x0003, "ca"),
		(0x0004, "zh-Hans"),
		(0x0005, "cs"),
		(0x0006, "da"),
		(0x0007, "de"),
		(0x0008, "el"),
		(0x0009, "en"),
		(0x000A, "es"),
		(0x000B, "fi"),
		(0x000C, "fr"),
		(0x000D, "he"),
		(0x000E, "hu"),
		(0x000F, "is"),
		(0x0010, "it"),
		(0x0011, "ja"),
		(0x0012, "ko"),
		(0x0013, "nl"),
		(0x0014, "no"),
		(0x0015, "pl"),
		(0x0016, "pt"),
		(0x0017, "rm"),
		(0x0018, "ro"),
		(0x0019, "ru"),
		(0x001A, "hr"),
		(0x001B, "sk"),
		(0x001C, "sq"),
		(0x001D, "sv"),
		(0x001E, "th"),
		(0x001F, "tr"),
		(0x0020, "ur"),
		(0x0021, "id"),
		(0x0022, "uk"),
		(0x0023, "be"),
		(0x0024, "sl"),
		(0x0025, "et"),
		(0x0026, "lv"),
		(0x0027, "lt"),
		(0x0028, "tg"),
		(0x0029, "fa"),
		(0x002A, "vi"),
		(0x002B, "hy"),
		(0x002C, "az"),
		(0x002D, "eu"),
		(0x002E, "hsb"),
		(0x002F, "mk"),
		(0x0030, "st"),
		(0x0031, "ts"),
		(0x0032, "tn"),
		(0x0033, "ve"),
		(0x0034, "xh"),
		(0x0035, "zu"),
		(0x0036, "af"),
		(0x0037, "ka"),
		(0x0038, "fo"),
		(0x0039, "hi"),
		(0x003A, "mt"),
		(0x003B, "se"),
		(0x003C, "ga"),
		(0x003D, "yi, reserved"),
		(0x003E, "ms"),
		(0x003F, "kk"),
		(0x0040, "ky"),
		(0x0041, "sw"),
		(0x0042, "tk"),
		(0x0043, "uz"),
		(0x0044, "tt"),
		(0x0045, "bn"),
		(0x0046, "pa"),
		(0x0047, "gu"),
		(0x0048, "or"),
		(0x0049, "ta"),
		(0x004A, "te"),
		(0x004B, "kn"),
		(0x004C, "ml"),
		(0x004D, "as"),
		(0x004E, "mr"),
		(0x004F, "sa"),
		(0x0050, "mn"),
		(0x0051, "bo"),
		(0x0052, "cy"),
		(0x0053, "km"),
		(0x0054, "lo"),
		(0x0055, "my"),
		(0x0056, "gl"),
		(0x0057, "kok"),
		(0x0058, "mni, reserved"),
		(0x0059, "sd"),
		(0x005A, "syr"),
		(0x005B, "si"),
		(0x005C, "chr"),
		(0x005D, "iu"),
		(0x005E, "am"),
		(0x005F, "tzm"),
		(0x0060, "ks"),
		(0x0061, "ne"),
		(0x0062, "fy"),
		(0x0063, "ps"),
		(0x0064, "fil"),
		(0x0065, "dv"),
		(0x0066, "bin, reserved"),
		(0x0067, "ff"),
		(0x0068, "ha"),
		(0x0069, "ibb, reserved"),
		(0x006A, "yo"),
		(0x006B, "quz"),
		(0x006C, "nso"),
		(0x006D, "ba"),
		(0x006E, "lb"),
		(0x006F, "kl"),
		(0x0070, "ig"),
		(0x0071, "kr, reserved"),
		(0x0072, "om"),
		(0x0073, "ti"),
		(0x0074, "gn"),
		(0x0075, "haw"),
		(0x0076, "la, reserved"),
		(0x0077, "so, reserved"),
		(0x0078, "ii"),
		(0x0079, "pap, reserved"),
		(0x007A, "arn"),
		(0x007B, "Neither defined nor reserved"),
		(0x007C, "moh"),
		(0x007D, "Neither defined nor reserved"),
		(0x007E, "br"),
		(0x007F, "Reserved for invariant locale behavior"),
		(0x0080, "ug"),
		(0x0081, "mi"),
		(0x0082, "oc"),
		(0x0083, "co"),
		(0x0084, "gsw"),
		(0x0085, "sah"),
		(0x0086, "qut"),
		(0x0087, "rw"),
		(0x0088, "wo"),
		(0x0089, "Neither defined nor reserved"),
		(0x008A, "Neither defined nor reserved"),
		(0x008B, "Neither defined nor reserved"),
		(0x008C, "prs"),
		(0x008D, "Neither defined nor reserved"),
		(0x008E, "Neither defined nor reserved"),
		(0x008F, "Neither defined nor reserved"),
		(0x0090, "Neither defined nor reserved"),
		(0x0091, "gd"),
		(0x0092, "ku"),
		(0x0093, "quc, reserved"),
		(0x0401, "ar-SA"),
		(0x0402, "bg-BG"),
		(0x0403, "ca-ES"),
		(0x0404, "zh-TW"),
		(0x0405, "cs-CZ"),
		(0x0406, "da-DK"),
		(0x0407, "de-DE"),
		(0x0408, "el-GR"),
		(0x0409, "en-US"),
		(0x040A, "es-ES_tradnl"),
		(0x040B, "fi-FI"),
		(0x040C, "fr-FR"),
		(0x040D, "he-IL"),
		(0x040E, "hu-HU"),
		(0x040F, "is-IS"),
		(0x0410, "it-IT"),
		(0x0411, "ja-JP"),
		(0x0412, "ko-KR"),
		(0x0413, "nl-NL"),
		(0x0414, "nb-NO"),
		(0x0415, "pl-PL"),
		(0x0416, "pt-BR"),
		(0x0417, "rm-CH"),
		(0x0418, "ro-RO"),
		(0x0419, "ru-RU"),
		(0x041A, "hr-HR"),
		(0x041B, "sk-SK"),
		(0x041C, "sq-AL"),
		(0x041D, "sv-SE"),
		(0x041E, "th-TH"),
		(0x041F, "tr-TR"),
		(0x0420, "ur-PK"),
		(0x0421, "id-ID"),
		(0x0422, "uk-UA"),
		(0x0423, "be-BY"),
		(0x0424, "sl-SI"),
		(0x0425, "et-EE"),
		(0x0426, "lv-LV"),
		(0x0427, "lt-LT"),
		(0x0428, "tg-Cyrl-TJ"),
		(0x0429, "fa-IR"),
		(0x042A, "vi-VN"),
		(0x042B, "hy-AM"),
		(0x042C, "az-Latn-AZ"),
		(0x042D, "eu-ES"),
		(0x042E, "hsb-DE"),
		(0x042F, "mk-MK"),
		(0x0430, "st-ZA"),
		(0x0431, "ts-ZA"),
		(0x0432, "tn-ZA"),
		(0x0433, "ve-ZA"),
		(0x0434, "xh-ZA"),
		(0x0435, "zu-ZA"),
		(0x0436, "af-ZA"),
		(0x0437, "ka-GE"),
		(0x0438, "fo-FO"),
		(0x0439, "hi-IN"),
		(0x043A, "mt-MT"),
		(0x043B, "se-NO"),
		(0x043D, "yi-001"),
		(0x043E, "ms-MY"),
		(0x043F, "kk-KZ"),
		(0x0440, "ky-KG"),
		(0x0441, "sw-KE"),
		(0x0442, "tk-TM"),
		(0x0443, "uz-Latn-UZ"),
		(0x0444, "tt-RU"),
		(0x0445, "bn-IN"),
		(0x0446, "pa-IN"),
		(0x0447, "gu-IN"),
		(0x0448, "or-IN"),
		(0x0449, "ta-IN"),
		(0x044A, "te-IN"),
		(0x044B, "kn-IN"),
		(0x044C, "ml-IN"),
		(0x044D, "as-IN"),
		(0x044E, "mr-IN"),
		(0x044F, "sa-IN"),
		(0x0450, "mn-MN"),
		(0x0451, "bo-CN"),
		(0x0452, "cy-GB"),
		(0x0453, "km-KH"),
		(0x0454, "lo-LA"),
		(0x0455, "my-MM"),
		(0x0456, "gl-ES"),
		(0x0457, "kok-IN"),
		(0x0458, "mni-IN, reserved"),
		(0x0459, "sd-Deva-IN, reserved"),
		(0x045A, "syr-SY"),
		(0x045B, "si-LK"),
		(0x045C, "chr-Cher-US"),
		(0x045D, "iu-Cans-CA"),
		(0x045E, "am-ET"),
		(0x045F, "tzm-Arab-MA"),
		(0x0460, "ks-Arab"),
		(0x0461, "ne-NP"),
		(0x0462, "fy-NL"),
		(0x0463, "ps-AF"),
		(0x0464, "fil-PH"),
		(0x0465, "dv-MV"),
		(0x0466, "bin-NG, reserved"),
		(0x0467, "ff-NG, ff-Latn-NG"),
		(0x0468, "ha-Latn-NG"),
		(0x0469, "ibb-NG, reserved"),
		(0x046A, "yo-NG"),
		(0x046B, "quz-BO"),
		(0x046C, "nso-ZA"),
		(0x046D, "ba-RU"),
		(0x046E, "lb-LU"),
		(0x046F, "kl-GL"),
		(0x0470, "ig-NG"),
		(0x0471, "kr-Latn-NG"),
		(0x0472, "om-ET"),
		(0x0473, "ti-ET"),
		(0x0474, "gn-PY"),
		(0x0475, "haw-US"),
		(0x0476, "la-VA"),
		(0x0477, "so-SO"),
		(0x0478, "ii-CN"),
		(0x0479, "pap-029, reserved"),
		(0x047A, "arn-CL"),
		(0x047C, "moh-CA"),
		(0x047E, "br-FR"),
		(0x0480, "ug-CN"),
		(0x0481, "mi-NZ"),
		(0x0482, "oc-FR"),
		(0x0483, "co-FR"),
		(0x0484, "gsw-FR"),
		(0x0485, "sah-RU"),
		(0x0486, "qut-GT, reserved"),
		(0x0487, "rw-RW"),
		(0x0488, "wo-SN"),
		(0x048C, "prs-AF"),
		(0x048D, "plt-MG, reserved"),
		(0x048E, "zh-yue-HK, reserved"),
		(0x048F, "tdd-Tale-CN, reserved"),
		(0x0490, "khb-Talu-CN, reserved"),
		(0x0491, "gd-GB"),
		(0x0492, "ku-Arab-IQ"),
		(0x0493, "quc-CO, reserved"),
		(0x0501, "qps-ploc"),
		(0x05FE, "qps-ploca"),
		(0x0801, "ar-IQ"),
		(0x0803, "ca-ES-valencia"),
		(0x0804, "zh-CN"),
		(0x0807, "de-CH"),
		(0x0809, "en-GB"),
		(0x080A, "es-MX"),
		(0x080C, "fr-BE"),
		(0x0810, "it-CH"),
		(0x0811, "ja-Ploc-JP, reserved"),
		(0x0813, "nl-BE"),
		(0x0814, "nn-NO"),
		(0x0816, "pt-PT"),
		(0x0818, "ro-MD"),
		(0x0819, "ru-MD"),
		(0x081A, "sr-Latn-CS"),
		(0x081D, "sv-FI"),
		(0x0820, "ur-IN"),
		(0x0827, "Neither defined nor reserved"),
		(0x082C, "az-Cyrl-AZ, reserved"),
		(0x082E, "dsb-DE"),
		(0x0832, "tn-BW"),
		(0x083B, "se-SE"),
		(0x083C, "ga-IE"),
		(0x083E, "ms-BN"),
		(0x083F, "kk-Latn-KZ, reserved"),
		(0x0843, "uz-Cyrl-UZ, reserved"),
		(0x0845, "bn-BD"),
		(0x0846, "pa-Arab-PK"),
		(0x0849, "ta-LK"),
		(0x0850, "mn-Mong-CN, reserved"),
		(0x0851, "bo-BT, reserved"),
		(0x0859, "sd-Arab-PK"),
		(0x085D, "iu-Latn-CA"),
		(0x085F, "tzm-Latn-DZ"),
		(0x0860, "ks-Deva-IN"),
		(0x0861, "ne-IN"),
		(0x0867, "ff-Latn-SN"),
		(0x086B, "quz-EC"),
		(0x0873, "ti-ER"),
		(0x09FF, "qps-plocm"),
		(0x0C00, "Locale without assigned LCID if the current user default locale."),
		(0x0C01, "ar-EG"),
		(0x0C04, "zh-HK"),
		(0x0C07, "de-AT"),
		(0x0C09, "en-AU"),
		(0x0C0A, "es-ES"),
		(0x0C0C, "fr-CA"),
		(0x0C1A, "sr-Cyrl-CS"),
		(0x0C3B, "se-FI"),
		(0x0C50, "mn-Mong-MN"),
		(0x0C51, "dz-BT"),
		(0x0C5F, "tmz-MA, reserved"),
		(0x0C6b, "quz-PE"),
		(0x1000, "Locale without assigned LCID if the current user default locale."),
		(0x1001, "ar-LY"),
		(0x1004, "zh-SG"),
		(0x1007, "de-LU"),
		(0x1009, "en-CA"),
		(0x100A, "es-GT"),
		(0x100C, "fr-CH"),
		(0x101A, "hr-BA"),
		(0x103B, "smj-NO"),
		(0x105F, "tzm-Tfng-MA"),
		(0x1401, "ar-DZ"),
		(0x1404, "zh-MO"),
		(0x1407, "de-LI"),
		(0x1409, "en-NZ"),
		(0x140A, "es-CR"),
		(0x140C, "fr-LU"),
		(0x141A, "bs-Latn-BA"),
		(0x143B, "smj-SE"),
		(0x1801, "ar-MA"),
		(0x1809, "en-IE"),
		(0x180A, "es-PA"),
		(0x180C, "fr-MC"),
		(0x181A, "sr-Latn-BA"),
		(0x183B, "sma-NO"),
		(0x1C01, "ar-TN"),
		(0x1C09, "en-ZA"),
		(0x1C0A, "es-DO"),
		(0x1C0C, "fr-029"),
		(0x1C1A, "sr-Cyrl-BA"),
		(0x1C3B, "sma-SE"),
		(0x2000, "Unassigned LCID locale temporarily assigned to LCID 0x3000."),
		(0x2001, "ar-OM"),
		(0x2008, "Neither defined nor reserved"),
		(0x2009, "en-JM"),
		(0x200A, "es-VE"),
		(0x200C, "fr-RE"),
		(0x201A, "bs-Cyrl-BA"),
		(0x203B, "sms-FI"),
		(0x2400, "Unassigned LCID locale temporarily assigned to LCID 0x3000."),
		(0x2401, "ar-YE"),
		(0x2409, "en-029, reserved"),
		(0x240A, "es-CO"),
		(0x240C, "fr-CD"),
		(0x241A, "sr-Latn-RS"),
		(0x243B, "smn-FI"),
		(0x2800, "Unassigned LCID locale temporarily assigned to LCID 0x3000."),
		(0x2801, "ar-SY"),
		(0x2809, "en-BZ"),
		(0x280A, "es-PE"),
		(0x280C, "fr-SN"),
		(0x281A, "sr-Cyrl-RS"),
		(0x2C00, "Unassigned LCID locale temporarily assigned to LCID 0x3000."),
		(0x2C01, "ar-JO"),
		(0x2C09, "en-TT"),
		(0x2C0A, "es-AR"),
		(0x2C0C, "fr-CM"),
		(0x2C1A, "sr-Latn-ME"),
		(0x3000, "Unassigned LCID locale temporarily assigned to LCID 0x3000."),
		(0x3001, "ar-LB"),
		(0x3009, "en-ZW"),
		(0x300A, "es-EC"),
		(0x300C, "fr-CI"),
		(0x301A, "sr-Cyrl-ME"),
		(0x3400, "Unassigned LCID locale temporarily assigned to LCID 0x3400."),
		(0x3401, "ar-KW"),
		(0x3409, "en-PH"),
		(0x340A, "es-CL"),
		(0x340C, "fr-ML"),
		(0x3800, "Unassigned LCID locale temporarily assigned to LCID 0x3800."),
		(0x3801, "ar-AE"),
		(0x3809, "en-ID, reserved"),
		(0x380A, "es-UY"),
		(0x380C, "fr-MA"),
		(0x3C00, "Unassigned LCID locale temporarily assigned to LCID 0x3C00."),
		(0x3C01, "ar-BH"),
		(0x3C09, "en-HK"),
		(0x3C0A, "es-PY"),
		(0x3C0C, "fr-HT"),
		(0x4000, "Unassigned LCID locale temporarily assigned to LCID 0x4000."),
		(0x4001, "ar-QA"),
		(0x4009, "en-IN"),
		(0x400A, "es-BO"),
		(0x4400, "Unassigned LCID locale temporarily assigned to LCID 0x4400."),
		(0x4401, "ar-Ploc-SA, reserved"),
		(0x4409, "en-MY"),
		(0x440A, "es-SV"),
		(0x4800, "Unassigned LCID locale temporarily assigned to LCID 0x4800."),
		(0x4801, "ar-145, reserved"),
		(0x4809, "en-SG"),
		(0x480A, "es-HN"),
		(0x4C00, "Unassigned LCID locale temporarily assigned to LCID 0x4C00."),
		(0x4C09, "en-AE"),
		(0x4C0A, "es-NI"),
		(0x5009, "en-BH, reserved"),
		(0x500A, "es-PR"),
		(0x5409, "en-EG, reserved"),
		(0x540A, "es-US"),
		(0x5809, "en-JO, reserved"),
		(0x580A, "es-419, reserved"),
		(0x5C09, "en-KW, reserved"),
		(0x5C0A, "es-CU"),
		(0x6009, "en-TR, reserved"),
		(0x6409, "en-YE, reserved"),
		(0x641A, "bs-Cyrl"),
		(0x681A, "bs-Latn"),
		(0x6C1A, "sr-Cyrl"),
		(0x701A, "sr-Latn"),
		(0x703B, "smn"),
		(0x742C, "az-Cyrl"),
		(0x743B, "sms"),
		(0x7804, "zh"),
		(0x7814, "nn"),
		(0x781A, "bs"),
		(0x782C, "az-Latn"),
		(0x783B, "sma"),
		(0x783F, "kk-Cyrl, reserved"),
		(0x7843, "uz-Cyrl"),
		(0x7850, "mn-Cyrl"),
		(0x785D, "iu-Cans"),
		(0x785F, "tzm-Tfng"),
		(0x7C04, "zh-Hant"),
		(0x7C14, "nb"),
		(0x7C1A, "sr"),
		(0x7C28, "tg-Cyrl"),
		(0x7C2E, "dsb"),
		(0x7C3B, "smj"),
		(0x7C3F, "kk-Latn, reserved"),
		(0x7C43, "uz-Latn"),
		(0x7C46, "pa-Arab"),
		(0x7C50, "mn-Mong"),
		(0x7C59, "sd-Arab"),
		(0x7C5C, "chr-Cher"),
		(0x7C5D, "iu-Latn"),
		(0x7C5F, "tzm-Latn"),
		(0x7C67, "ff-Latn"),
		(0x7C68, "ha-Latn"),
		(0x7C92, "ku-Arab"),
		(0xF2EE, "reserved"),
		(0xE40C, "fr-015, reserved"),
		(0xEEEE, "reserved"),
	];
	pub fn to_str(&self) -> Option<&'static str> {
		Self::WINDOWS_LANGUAGE_IDS
			.binary_search_by_key(&self.0, |v| v.0)
			.map(|v| Self::WINDOWS_LANGUAGE_IDS.get(v).map(|v| v.1))
			.ok()
			.flatten()
	}
}
impl core::fmt::Debug for WindowsLanguageId {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		write!(f, "{}", self.to_str().unwrap_or("Unkonw"))
	}
}
